#ifndef STX_PLATFORM_POSIX_THREAD_CONDITIONAL_VARIABLE_HPP
#define STX_PLATFORM_POSIX_THREAD_CONDITIONAL_VARIABLE_HPP

#include <stx/platform/posix/thread/common.hpp>
#include <stx/platform/posix/thread/conditional_variable_attributes.hpp>

namespace stx {

namespace posix {

class contidional_variable: noncopyable
{
public:
    
    typedef contidional_variable this_type;
    
    contidional_variable()
    {
        int ret = pthread_cond_init(&handle_, NULL);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_cond_init");
        }
    }
    
    contidional_variable(const conditional_variable_attributes& attr)
    {
        int ret = pthread_cond_init(&handle_, attr.handle());
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_cond_init");
        }
    }
    
    ~contidional_variable()
    {
        int ret = pthread_cond_destroy(&handle_);
        if (ret) {
            STX_DESTRUCTOR_SYSTEM_ERROR_VAL(ret, "pthread_cond_destroy");
        }
    }
    
    void signal()
    {
        int ret = pthread_cond_signal(&handle_);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_cond_signal");
        }
    }
    
    void broadcast()
    {
        int ret = pthread_cond_broadcast(&handle_);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_cond_broadcast");
        }
    }
    
    void wait(mutex& mutex_)
    {
        int ret = pthread_cond_wait(&handle_, mutex_.handle());
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_cond_wait");
        }
    }
    
    bool timed_wait(mutex& mutex_, const struct timespec& timeout)
    {
        int ret = pthread_cond_timedwait(&handle_, mutex_.handle(), &timeout);
        if (ret == ETIMEDOUT) {
            return false;
        } else {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_cond_timedwait");
        }
        return true;
    }
    
    typedef pthread_cond_t handle_type;
    
    handle_type* handle()
    {
        return &handle_;
    }
    
    const handle_type* handle() const
    {
        return &handle_;
    }
    
private:
    
    handle_type handle_;
};

} // namespace posix

} // namespace stx

#endif // STX_PLATFORM_POSIX_THREAD_CONDITIONAL_VARIABLE_HPP
